﻿using trace = System.Diagnostics.Trace;
using System.Collections.Generic;
using System.IO;
using System;
namespace gxc2csharp.Translator.GxcToCTransform 
{
   public partial class GxcParser 
   {
      public string GxName{get;set;}
      public string GxVersion { get; set; }
      public string GxDescription { get; set; }
      public Dictionary<string, string> GxVariables { get; set; }
      public List<string> PInvokeFunctions { get; set; }
      public Dictionary<string, GxcToCsharpParser.GrcParser.GrcParser> GrcResources;
      int LinesOfComments { get; set; }
      int CyclomaticComplexity { get; set; }
      Dictionary<string, int> Operators;
      public int LinesOfCode{get;set;}
      
      private void CountBlockCommentLines(string commnetText)
      {
          string[] newlines = commnetText.Split('\n');
          LinesOfComments += newlines.Length;
      }
      private void IncrementOperatorCount(string text)
      {
          if (!Operators.ContainsKey(text))
              Operators.Add(text,0);
          Operators[text]++;

      }
      public GxcToCsharpParser.Metrics.CodeMetrics GetMetrics()
      {
          GxcToCsharpParser.Metrics.CodeMetrics metrics = new GxcToCsharpParser.Metrics.CodeMetrics();
          double totalOperators = 0;//n2
          foreach(int value in Operators.Values)
          {
              totalOperators+=value;
          }
          double programLength =GxVariables.Count+totalOperators; //N
          double vocabularySize = (GxVariables.Count + Operators.Count);//n
          double programVolume = programLength * Math.Log(vocabularySize, 2);//  V = N * log2(n) 
          double difficultyLevel = (GxVariables.Count / 2.0) * (programLength / totalOperators); //D=( n1 / 2 ) * ( 2 / n2 ) 
          double programLevel = 1 / difficultyLevel;//L=1/D
          double effortToImplement = programVolume * difficultyLevel;//E=V*D
          double timeToImplement = effortToImplement / 18;//T=E/18
          double numberOfDeliveredBugs= Math.Pow(effortToImplement,2/3)/3000;//   B = ( E ** (2/3) ) / 3000  
          int maintainabilityIndex = (int)Math.Round(Math.Max(0, (171 - 5.2 * Math.Log(programVolume) - 0.23 * (CyclomaticComplexity) - 16.2 * Math.Log(LinesOfCode - LinesOfComments)) * 100 / 171));
          metrics.MaintainabilityIndex = maintainabilityIndex;
          metrics.CyclomaticComplexity = CyclomaticComplexity;
          metrics.LinesOfCode = Math.Max(0,LinesOfCode - LinesOfComments);
          metrics.GxCoupling = 0;



          return metrics;
          
      }

      private void AddVariables(string type, int size, List<string> variables)
      {
         foreach (string variable in variables)
            GxVariables.Add(variable, type + "_" + size);
      }
      private void AddFunctionDeclaration(string functionName, string dll, string returnType, List<string> functionArgsType)
      {
         if (dll == "_licensed" || dll == "_extended" || dll == "_public" ||
            dll == "_licensed_app" || dll == "_extended_app" || dll == "_public_app")
            return;
         System.Diagnostics.Trace.TraceInformation("PInvoke for function{0} in dll {1}.dll produced", functionName, dll);
         string pinvoke = "DllImport(\""+dll+".dll\", SetLastError=true)]";
         pinvoke +="\n static extern "+returnType+"(";
         int i = 0;
         foreach (string type in functionArgsType)
         {
            pinvoke += type + " arg" + i.ToString();
            pinvoke += ",";
            i++;

         }
         pinvoke = pinvoke.Remove(pinvoke.Length - 1) + ");";
         PInvokeFunctions.Add(pinvoke);

      }
      /// <summary>
      /// Reads the in GRC file.
      /// </summary>
      /// <param name="grFilePath">The gr file path.</param>
      private void ReadInGrcFile(string grFilePath)
      {
         try
         {
            string fileName = Path.GetFileNameWithoutExtension(grFilePath) + ".grc";
            System.Diagnostics.Trace.TraceInformation("Trying to read grc file {0} ", fileName);
            if (File.Exists(fileName))
            {
               if (GrcResources.ContainsKey(fileName) == false)
               {
                  GxcToCsharpParser.GrcParser.GrcParser parser = new GxcToCsharpParser.GrcParser.GrcParser();
                  parser.ParseFile(fileName);
                  GrcResources.Add(fileName, parser);
               }
            }
         }
         catch (Exception e)
         {
            System.Diagnostics.Trace.TraceError("GRC read error{0}",e.Message);
         }
      }
      
#if DEBUG
     //private TextWriter trace = Console.Out; // This mirrors the behaviour we're overloading

      // Override the parser trace method so we can control where the information goes
      public override void TraceIn(string ruleName, int ruleIndex)
      {
         
         TraceIn(ruleName, ruleIndex, input.LT(1));
      }

      // Override the parser trace method so we can control where the information goes
      public override void TraceIn(string ruleName, int ruleIndex, object inputSymbol)
      {
         trace.TraceInformation("enter " + ruleName + " " + inputSymbol);
         if (state.backtracking > 0)
         {
            trace.TraceInformation(" backtracking=" + state.backtracking);
         }
         trace.TraceInformation(string.Empty);
      }

      // Override the parser trace method so we can control where the information goes
      public override void TraceOut(string ruleName, int ruleIndex, object inputSymbol)
      {
         
         trace.TraceInformation("exit " + ruleName + " " + inputSymbol);
         if (state.backtracking > 0)
         {
            trace.TraceInformation(" backtracking=" + state.backtracking);
            trace.TraceInformation(state.failed ? " FAILED!" : " succeeded");
         }
         else
         {
            trace.WriteLine(string.Empty);
         }
      }

      // Override the parser trace method so we can control where the information goes
      public override void TraceOut(string ruleName, int ruleIndex)
      {
         TraceOut(ruleName, ruleIndex, input.LT(1));
      }
#endif 
   }
}